﻿#include<iostream>
using namespace std;

#if 0
/************** 虚函数重写 *********************/
//**虚函数：被virtual修饰的 类成员函数 称为虚函数
//**只能用来修饰 非静态的成员函数**//
//virtual void func()	//err
//{
//	cout << 1 << endl;
//}

//class Person {
//public:
//	void BuyTicket() { cout << "买票-全价" << endl; }
//};
//
//class Student : public Person {
//public:
//	void BuyTicket() { cout << "买票-半价" << endl; }
//};
//
//void test01()
//{
//	Person p;
//	p.BuyTicket();
//	Student s;
//	s.BuyTicket();
//
//	Person* ptr = &s;	//ptr指向的是Student，但却调用了Person的函数，为了解决这个问题，引入了虚函数
//	ptr->BuyTicket(); //买票 - 全价
//}

/*
* 虚函数重写：派生类中有一个跟基类完全相同的虚函数（函数名、返回值类型、参数列表完全相同）
* 重写是更严格的隐藏
*/
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
};

class Student : public Person {
public:
	//父类有virtual，这里不加virtual也构成重写
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
};

void test02()
{
	Person p;
	Student s;
	Person* ptr = &s;	//这样，ptr指向Student，就调用Student里面的函数
	ptr->BuyTicket();
	Person& ps = s;		//这样也行
	ps.BuyTicket();
	//ps.Person::BuyTicket();	//但指定作用域就不是多态了。一般不会这样写
}
/// 多态条件：
/// 1、虚函数重写
/// 2、父类指针/引用调用虚函数（必须是父类）

/*
* 多态调用：看指向的对象类型，指向谁就调用谁的虚函数
* 普通调用：看调用者的类型，调用者是什么类型就调用该类型
*/

/*派生类重写虚函数可以不加virtual，但建议加上
* 虚函数重写的两个例外：
* 1、协变（基类与派生类的虚函数返回值类型不同，但是父子关系）(了解就行)
*/
class A {};
class B : public A {};

class Person {
public:
	virtual A* f() { 
		cout << "买票-全价" << endl;
		return new A; 
	}
	virtual Person& func() {
		cout << "买票-全价" << endl;
		return *this;
	}
};

class Student : public Person {
public:
	//这里返回值是B*，Person那里是A*，但由于B继承了A，称为协变（父子关系）。如果B没有继承A，就会编译错误
	//返回值必须是指针或引用！！
	virtual B* f() { 
		cout << "买票-半价" << endl; 
		return new B; 
	}
	virtual Student& func() {
		cout << "买票-半价" << endl;
		return *this;
	}
};
void test03()
{
	Student s;
	Person* ptr = &s;
	ptr->func();
}

/*
* 2、析构函数的重写。函数名不同：一个是：~Person，另一个是：~Student。但其实编译器后期都会处理成destructor
* 析构函数一定建议写成虚函数
*/
class Person {
public:
	virtual ~Person() { cout << "~Person()" << endl; }
};

class Student : public Person {
public:
	virtual ~Student() { cout << "~Student()" << endl; }
};
void test04()
{
	Person* ptr = new Student;
	delete ptr;
}
#endif

/********* C++11 override 和 ﬁnal *********/
////override: 检查派生类虚函数是否重写了基类某个虚函数，如果没有重写编译报错。
//class Car {
//public:
//	void Drive() {}
//};
//
//class Benz :public Car {
//public:
//	//err，没有完成重写
//	virtual void Drive() override { cout << "Benz-舒适" << endl; }
//};

////ﬁnal：修饰虚函数，表示该虚函数不能再被重写，在父类加
//class Car
//{
//public:
//	virtual void Drive() final {}
//};
//
//class Benz :public Car
//{
//public:
//	//err，父类虚函数加了final
//	virtual void Drive() { cout << "Benz-舒适" << endl; }
//};

////final 修饰类，表示不能被别的类继承
//class A final
//{};
//class B : public A
//{};
//void test05()
//{
//	B b;
//}

////不想被继承还可以把构造函数设为私有--》,这样就不能实例化出对象了.了解就行
//class A
//{
//public:
//	static A Create()
//	{
//		return A();
//	}
//private:
//	A()
//	{}
//};
//class B : public A
//{};
//void test06()
//{
//	A a = A::Create();
//}

/*
重载：同一作用域，函数名相同，参数不同（类型或个数或顺序）。不管返回值的事
重写(覆盖)：分别在父类和子类作用域，函数名、参数、返回值完全相同(协变除外)，还得是虚函数（子类可以不加virtual）
重定义(隐藏)：分别在父类和子类作用域，函数名相同就行
*/

/*********** 抽象类 **********/
//**纯虚函数：在虚函数的后面写上 = 0
// 包含纯虚函数的类叫做抽象类（也叫接口类）抽象类不能实例化出对象，但可以有抽象类的引用
//class A		//抽象类
//{
//public:
//	//纯虚函数
//	virtual void func() = 0
//	{}
//};
//
//class B : public A
//{
//
//};
//void test07()
//{
//	//A a;	//err, 不能实例化出对象
//	B b;	//err, B继承A，但没有重写，也不能实例化对象
//	A& a = b;	//可以引用
//}

#if 0
class A
{
public:
	virtual void func(int val = 1)
	{
		cout << "A->" << val << endl;
	}
};

class B : public A
{
public:
	void func(int a = 0)
	{
		cout << "B->" << a << endl;
	}
};

void test08()
{
	A* p = new B;
	p->func();	//B->1
	//虚函数重写只是对花括号里面的内容进行改写，函数参数还是原来那个，缺省值也是原来的
}

/*笔试题：以下程序输出结果是什么？？*/
class A
{
public:
	virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }
	virtual void test() { func(); }	//A* this，调用func构成多态
};

class B : public A
{
	//**派生类的重写只看实现（花括号部分）
private:	//这里虽然是私有，但由于父类是公有，并且公有继承，所以也可以调到
	void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};

int main()
{
	B* p = new B;
	p->test();
	return 0;
}

class A
{
public:
	virtual void func(int a = 1)
	{
		cout << "A->" << a << endl;
	}
};

class B : public A
{
private:
	void func(int a = 0)
	{
		cout << "B->" << a << endl;
	}
};
void test09()
{
	A* p = new B;
	p->func();
}


int main1 ()
{
	test10();
	return 0;
}

/****** 笔试题 ******/
class Base1 { public:  int _b1; };
class Base2 { public:  int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };

int main() {
	Derive d;
	Base1* p1 = &d;
	Base2* p2 = &d;
	Derive* p3 = &d;
	// p1 == p3 != p2
	return 0;
}
#endif
